import fs from 'node:fs'
import path from 'node:path'
import { exit } from 'node:process'
import { Command } from 'commander'
import inquirer from 'inquirer'
import * as yocto from 'yoctocolors'
import { generateBanner } from '../banner.js'
import {
  DbOrmDiscussionUrl,
  DiscussionUrl,
  DocsUrl,
  RepositoryUrl,
} from '../urls.js'

const initCommand = new Command('init').description(
  'guide you interactively through the setup',
)

// Map user-friendly selections to the correct --format value
const formatMap: Record<string, string> = {
  PostgreSQL: 'postgres',
  'Ruby on Rails (schema.rb)': 'schemarb',
  'Prisma (schema.prisma)': 'prisma',
  'Drizzle (schema.ts) [Experimental]': 'drizzle',
  'MySQL (via tbls)': 'tbls',
  'SQLite (via tbls)': 'tbls',
  'BigQuery (via tbls)': 'tbls',
  tbls: 'tbls',
}

/**
 * Display welcome message for the init command
 */
const displayWelcomeMessage = () => {
  console.info(`
👾  Welcome to the @liam-hq/cli setup process! 👾

This \`init\` subcommand will guide you interactively through the setup.

${yocto.greenBright('🌟 This init command is a work in progress! 🌟')}
We're continuously improving it. Don't forget to run \`npx @liam-hq/cli init\` after updates for the latest features.

💡 Have feedback? Share it with us!
Visit ${yocto.blueBright(DiscussionUrl)} to submit ideas or report issues.

🌟️ ${yocto.bold('Love Liam ERD')}? Help us grow by starring our GitHub repository:
${yocto.blueBright(RepositoryUrl)}

----
Now, let's get started with setting up your Liam ERD project.
  `)
}

/**
 * Handle PostgreSQL specific prompts
 * @returns The input file path if provided
 */
const handlePostgresPrompts = async (): Promise<string> => {
  // Ask if pg_dump .sql can be used
  const { usePgDump } = await inquirer.prompt<{ usePgDump: boolean }>([
    {
      type: 'confirm',
      name: 'usePgDump',
      message:
        'Can we use an .sql file generated by pg_dump? (Recommended: `pg_dump --schema-only`)',
      default: false,
    },
  ])

  if (usePgDump) {
    // If yes, ask for the path
    const { dumpFilePath } = await inquirer.prompt<{ dumpFilePath: string }>([
      {
        type: 'input',
        name: 'dumpFilePath',
        message: 'What is your dump file path?',
        default: 'schema.sql',
      },
    ])
    return dumpFilePath
  }

  // If no, do not ask for path—just inform
  console.info(`
${yocto.yellow(
  'Please run `pg_dump --schema-only` later to generate a dump file you can use with Liam ERD.',
)}
`)
  return ''
}

/**
 * Handle Drizzle specific prompts
 * @returns Object with input file path and support status
 */
const handleDrizzlePrompts = async (): Promise<{
  inputFilePath: string
  cannotSupportNow: boolean
}> => {
  const { schemaFilePath } = await inquirer.prompt<{
    schemaFilePath: string
  }>([
    {
      type: 'input',
      name: 'schemaFilePath',
      message: 'What is the path to your Drizzle schema file?',
      default: 'src/db/schema.ts',
    },
  ])

  console.info(`
${yocto.yellow(
  'Note: Drizzle support is experimental. Please let us know if you encounter any issues.',
)}
`)

  return { inputFilePath: schemaFilePath, cannotSupportNow: false }
}

/**
 * Handle tbls specific prompts
 * @returns The schema file path
 */
const handleTblsPrompts = async (): Promise<string> => {
  const { schemaFilePath } = await inquirer.prompt<{
    schemaFilePath: string
  }>([
    {
      type: 'input',
      name: 'schemaFilePath',
      message:
        'What is the path to the schema.json file? (It is located in the output directory of the tbls doc)',
      default: 'docs/schema.json',
    },
  ])
  return schemaFilePath
}

/**
 * Handle tbls via other database prompts
 * @returns The default schema.json path
 */
const handleTblsViaOtherPrompts = (): string => {
  console.info(`
${yocto.yellow("Note: Direct support is not available yet. You'll need to use tbls as a bridge.")}

To use tbls with Liam ERD:

1. Install tbls from: https://github.com/k1LoW/tbls?tab=readme-ov-file#install

2. Generate a schema.json file using tbls:

${yocto.blueBright('   $ tbls out -t json -o schema.json')}

For more details about using tbls with Liam ERD, see:
${yocto.blueBright(`${DocsUrl}/parser/supported-formats/tbls`)}

Want direct support without using tbls? Let us know at:
${yocto.blueBright(DbOrmDiscussionUrl)}
`)
  return 'schema.json'
}

/**
 * Handle Rails or Prisma specific prompts
 * @param dbOrOrm The selected database or ORM
 * @returns The schema file path
 */
const handleRailsOrPrismaPrompts = async (dbOrOrm: string): Promise<string> => {
  let defaultSchemaPath = ''
  if (dbOrOrm === 'Ruby on Rails (schema.rb)') {
    defaultSchemaPath = 'db/schema.rb'
  } else if (dbOrOrm === 'Prisma (schema.prisma)') {
    defaultSchemaPath = 'prisma/schema.prisma'
  }

  const { schemaFilePath } = await inquirer.prompt<{
    schemaFilePath: string
  }>([
    {
      type: 'input',
      name: 'schemaFilePath',
      message: 'What is your schema file path?',
      default: defaultSchemaPath,
    },
  ])
  return schemaFilePath
}

/**
 * Display unsupported technology message and exit
 */
const displayUnsupportedMessage = () => {
  console.info(`
💔 ${yocto.yellowBright("For other DBs or ORMs, Sorry we don't support them yet")} 💔

Visit ${yocto.yellowBright(DbOrmDiscussionUrl)} to suggest support for your database or ORM!

For more details about Liam ERD usage and advanced configurations, check out:
${yocto.blueBright(DocsUrl)}
`)
  exit(0)
}

/**
 * Display next steps based on the selected technology and input file
 * @param dbOrOrm The selected database or ORM
 * @param inputFilePath The input file path if provided
 * @param selectedFormat The selected format for the build command
 */
const displayNextSteps = (
  dbOrOrm: string,
  inputFilePath: string,
  selectedFormat: string,
) => {
  console.info('\n--- Next Steps ---')
  let stepNum = 1

  if (dbOrOrm.includes('(via tbls)')) {
    console.info(`${stepNum}) Build your ERD using the generated schema.json:`)
    stepNum++
    console.info(
      yocto.blueBright(
        '   $ npx @liam-hq/cli erd build --input schema.json --format tbls',
      ),
    )
  } else if (inputFilePath) {
    console.info(
      `${stepNum}) Build your ERD from the specified file using the following command:`,
    )
    stepNum++
    console.info(
      yocto.blueBright(
        `   $ npx @liam-hq/cli erd build --input ${inputFilePath} --format ${selectedFormat}`,
      ),
    )
  } else {
    // If the user didn't specify a dump file (e.g., said "No" to pg_dump)
    console.info(
      `${stepNum}) Once you generate a dump file, build your ERD using the following command:`,
    )
    stepNum++
    console.info(
      yocto.blueBright(
        '   $ npx @liam-hq/cli erd build --input <schema.sql> --format postgres',
      ),
    )
  }

  console.info(
    `\n${stepNum}) Start your favorite httpd for serving dist. e.g.:`,
  )
  console.info(yocto.blueBright('   $ npx serve dist/'))
  console.info(yocto.blueBright('   or'))
  console.info(yocto.blueBright('   $ npx http-server -c-1 dist/'))
}

/**
 * Generate GitHub Actions workflow file
 * @param addGhActions Whether to add GitHub Actions
 * @param dbOrOrm The selected database or ORM
 * @param inputFilePath The input file path if provided
 * @param selectedFormat The selected format for the build command
 */
const generateGitHubActions = (
  addGhActions: boolean,
  dbOrOrm: string,
  inputFilePath: string,
  selectedFormat: string,
) => {
  if (!addGhActions) return

  // The user might not have a path if they chose "No" to pg_dump or if Drizzle was chosen
  const effectivePath = inputFilePath || '<schema.sql>'
  let setupSteps = ''

  if (dbOrOrm.includes('(via tbls)')) {
    setupSteps = `
      - name: Setup tbls
        uses: k1low/setup-tbls@v1

      - name: Generate schema.json
        run: tbls out -t json -o schema.json
`
  }

  const workflowContent = `name: ERD Build
on:
  push:
    branches: [ "main" ]

jobs:
  build-erd:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
${setupSteps}
      - name: Generate ER Diagrams
        run: npx @liam-hq/cli erd build --input ${effectivePath} --format ${selectedFormat}

    # - Next step: Deploy ERD \`./dist\` to your preferred hosting service for easy sharing and access.
`

  const workflowDir = path.join(process.cwd(), '.github', 'workflows')
  const workflowPath = path.join(workflowDir, 'erd.yml')

  try {
    fs.mkdirSync(workflowDir, { recursive: true })
    fs.writeFileSync(workflowPath, workflowContent, 'utf-8')
    console.info(
      yocto.greenBright(
        `\n✔ Created GitHub Actions workflow at: ${workflowPath}\n`,
      ),
    )
  } catch (err) {
    console.error(
      yocto.redBright(
        `\nFailed to create GitHub Actions workflow file: ${err}\n`,
      ),
    )
  }
}

/**
 * Main action function for the init command
 */
initCommand.action(async () => {
  await generateBanner()
  // Display welcome message
  displayWelcomeMessage()

  // Step 1: Ask which technology/ORM the user is using
  const { dbOrOrm } = await inquirer.prompt<{ dbOrOrm: string }>([
    {
      type: 'list',
      name: 'dbOrOrm',
      message: 'Which Technology (database or ORM) are you using?',
      choices: [
        'PostgreSQL',
        'Ruby on Rails (schema.rb)',
        'Prisma (schema.prisma)',
        'Drizzle (schema.ts) [Experimental]',
        'tbls',
        'MySQL (via tbls)',
        'SQLite (via tbls)',
        'BigQuery (via tbls)',
        'Others',
      ],
      default: 'PostgreSQL',
    },
  ])

  // Step 2: Depending on dbOrOrm, ask follow-up questions
  let inputFilePath = ''
  let cannotSupportNow = false

  if (dbOrOrm === 'PostgreSQL') {
    inputFilePath = await handlePostgresPrompts()
  } else if (dbOrOrm === 'Drizzle (schema.ts) [Experimental]') {
    const result = await handleDrizzlePrompts()
    inputFilePath = result.inputFilePath
    cannotSupportNow = result.cannotSupportNow
  } else if (dbOrOrm === 'tbls') {
    inputFilePath = await handleTblsPrompts()
  } else if (dbOrOrm.includes('(via tbls)')) {
    inputFilePath = handleTblsViaOtherPrompts()
  } else if (dbOrOrm === 'Others') {
    cannotSupportNow = true
  } else {
    // For Rails/Prisma
    inputFilePath = await handleRailsOrPrismaPrompts(dbOrOrm)
  }

  if (cannotSupportNow) {
    displayUnsupportedMessage()
  }

  // Step 3: Ask if the user wants GitHub Actions
  const { addGhActions } = await inquirer.prompt<{ addGhActions: boolean }>([
    {
      type: 'confirm',
      name: 'addGhActions',
      message: 'Generate GitHub Actions Workflow?',
      default: false,
    },
  ])

  // Determine the --format value based on user selection
  const selectedFormat = formatMap[dbOrOrm] || 'postgres'

  // Show docs link
  console.info(`
For more details about Liam ERD usage and advanced configurations, check out:
${yocto.blueBright(DocsUrl)}
`)

  // Display next steps
  displayNextSteps(dbOrOrm, inputFilePath, selectedFormat)

  // Generate GitHub Actions file if requested
  generateGitHubActions(addGhActions, dbOrOrm, inputFilePath, selectedFormat)

  console.info(
    yocto.greenBright(`
✅ Setup complete! Enjoy using Liam ERD to visualize your database schema!`),
  )
})

export { initCommand }
